/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package com.googlecode.ivybeans.module;

import com.googlecode.ivybeans.facade.ResolvedIvyLibrary;
import com.googlecode.ivybeans.module.classpath.ClassPathScope;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.netbeans.api.project.Project;
import org.netbeans.spi.project.AuxiliaryConfiguration;
import org.openide.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * 
 * @author lforet
 */
public class IvyConfigurationHelper {

    public static final String PROJECT_CONFIGURATION_NAMESPACE = "http://code.google.com/p/ivybeans/ns/ivy-module/1"; // NOI18N
    public static final String IVY_CONFIGURATION_ELEMENT_NAME = "ivyConfiguration"; //NO I18N
    public static final String DESCRIPTOR_FILE_ELEMENT_NAME = "descriptorFile"; //NO I18N
    public static final String SETTINGS_FILE_ELEMENT_NAME = "settingsFile"; //NO I18N
    public static final String CONFIGURATION_MAPPING_ELEMENT_NAME = "configurationMapping"; //NO I18N
    public static final String CLASSPATH_SCOPE_ELEMENT_NAME = "scope"; //NO I18N
    public static final String CLASSPATH_SCOPE_NAME_ATTR = "name"; //NO I18N
    public static final String CLASSPATH_SCOPE_CONFS_ATTR = "confs"; //NO I18N
    public final static String CONF_SEPARATOR = ",";
    private static IvyConfigurationHelper instance;

    private IvyConfigurationHelper() {
    }

    public static IvyConfigurationHelper getInstance() {
        if (instance == null) {
            instance = new IvyConfigurationHelper();
        }
        return instance;
    }

    public IvyLibraryController initController(Project project, AuxiliaryConfiguration auxiliaryConfiguration) {
        boolean enabled = false;
        String descriptorFilename = null;
        String settingsFilename = null;
        IvyLibraryController.ConfigurationMapping configurationMapping = null;

        Element ivyConfElt = auxiliaryConfiguration.getConfigurationFragment(IVY_CONFIGURATION_ELEMENT_NAME, PROJECT_CONFIGURATION_NAMESPACE, true);
        if (ivyConfElt != null) {
            enabled = true;

            Element descriptorFileElt = (Element) ivyConfElt.getElementsByTagName(DESCRIPTOR_FILE_ELEMENT_NAME).item(0);
            if (descriptorFileElt != null) {
                descriptorFilename = descriptorFileElt.getTextContent();
            }

            Element settingsFileElt = (Element) ivyConfElt.getElementsByTagName(SETTINGS_FILE_ELEMENT_NAME).item(0);
            if (settingsFileElt != null) {
                settingsFilename = settingsFileElt.getTextContent();
            }

            Element configurationMappingElement = (Element) ivyConfElt.getElementsByTagName(CONFIGURATION_MAPPING_ELEMENT_NAME).item(0);
            if (configurationMappingElement != null) {
                NodeList scopeElements = configurationMappingElement.getElementsByTagName(CLASSPATH_SCOPE_ELEMENT_NAME);
                configurationMapping = new IvyLibraryController.ConfigurationMapping();
                for (int i = 0; i < scopeElements.getLength(); i++) {
                    Element currentScopeElement = (Element) scopeElements.item(i);
                    ClassPathScope cpScope = ClassPathScope.valueOf(currentScopeElement.getAttribute(CLASSPATH_SCOPE_NAME_ATTR));
                    String[] confs = tokenize(currentScopeElement.getAttribute(CLASSPATH_SCOPE_CONFS_ATTR));
                    configurationMapping.put(cpScope, confs, ResolvedIvyLibrary.EMPTY_RESOLVED);
                }
            }
        }
        return new IvyLibraryController(project, enabled, descriptorFilename, settingsFilename, configurationMapping);
    }

    public void clean(Project project) {
        AuxiliaryConfiguration auxiliaryConfiguration = project.getLookup().lookup(AuxiliaryConfiguration.class);
        assert auxiliaryConfiguration != null;
        auxiliaryConfiguration.removeConfigurationFragment(IVY_CONFIGURATION_ELEMENT_NAME, PROJECT_CONFIGURATION_NAMESPACE, true);
    }

    public void store(Project project) {
        clean(project);
        IvyLibraryController ivyLibraryController = project.getLookup().lookup(IvyLibraryController.class);
        if (ivyLibraryController.isIvyEnabled()) {
            AuxiliaryConfiguration auxiliaryConfiguration = project.getLookup().lookup(AuxiliaryConfiguration.class);
            Document doc = XMLUtil.createDocument("whatever", null, null, null);
            Element fragment = doc.createElementNS(PROJECT_CONFIGURATION_NAMESPACE, IVY_CONFIGURATION_ELEMENT_NAME);
            
            File descriptorFile = ivyLibraryController.getDescriptorFile();
            if (descriptorFile != null) {
                Element descriptorFileElement = doc.createElement(DESCRIPTOR_FILE_ELEMENT_NAME);
                fragment.appendChild(descriptorFileElement);
                String descriptorPath = FileHelper.getInstance().getPath(project.getProjectDirectory(), descriptorFile);
                descriptorFileElement.appendChild(doc.createTextNode(descriptorPath));
            }
            File settingsFile = ivyLibraryController.getSettingsFile();
            URL settingsUrl = ivyLibraryController.getSettingsURL();
            if (settingsFile != null) {
                Element settingsFileElement = doc.createElement(SETTINGS_FILE_ELEMENT_NAME);
                fragment.appendChild(settingsFileElement);
                String settingsPath = FileHelper.getInstance().getPath(project.getProjectDirectory(), settingsFile);
                settingsFileElement.appendChild(doc.createTextNode(settingsPath));
            } else if (settingsUrl != null) {
                Element settingsFileElement = doc.createElement(SETTINGS_FILE_ELEMENT_NAME);
                fragment.appendChild(settingsFileElement);
                settingsFileElement.appendChild(doc.createTextNode(settingsUrl.toString()));
            }
            Element configurationMappingElement = doc.createElement(CONFIGURATION_MAPPING_ELEMENT_NAME);
            fragment.appendChild(configurationMappingElement);
            for (ClassPathScope scope : ClassPathScope.values()) {
                Element scopeElement = doc.createElement(CLASSPATH_SCOPE_ELEMENT_NAME);
                scopeElement.setAttribute(CLASSPATH_SCOPE_NAME_ATTR, scope.name());
                String confs = untokenize(ivyLibraryController.getConfigurationMapping().getConfiguration(scope));
                scopeElement.setAttribute(CLASSPATH_SCOPE_CONFS_ATTR, confs);
                configurationMappingElement.appendChild(scopeElement);
            }
            auxiliaryConfiguration.putConfigurationFragment(fragment, true);
        }
    }

    public String[] tokenize(String confs) {
        StringTokenizer tokenizer = new StringTokenizer(confs, CONF_SEPARATOR);
        List<String> tokens = new ArrayList<String>();
        while (tokenizer.hasMoreTokens()) {
            tokens.add(tokenizer.nextToken().trim());
        }
        return tokens.toArray(new String[0]);
    }
    
    public String untokenize(String[] tokens) {
        String toReturn = "";
        if (tokens == null || tokens.length == 0) {
            return toReturn;
        }
        for (int i = 0; i < tokens.length -1; i++ ) {
            toReturn += tokens[i]+ CONF_SEPARATOR;
        }
        toReturn += tokens[tokens.length - 1];
        return toReturn;
    }
}
